﻿namespace $safeprojectname$
{
    using System;
    using System.Diagnostics;
    using System.Globalization;
    using System.IO;
    using System.Reflection;
    using $safeprojectname$.Properties;

    /// <summary>
    /// The <see cref="Program"/>
    ///   class provides the entry point into the application.
    /// </summary>
    public static class Program
    {
        /// <summary>
        /// The Main method is the entry point to the application.
        /// </summary>
        /// <param name="args">
        /// The command line arguments.
        /// </param>
        [STAThread]
        public static void Main(String[] args)
        {
            const String PackageExtension = "$packageExtension$";

            Boolean isExtractAction = DetermineExtractAction(args);
            FileVersionInfo info = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);
            String extractionPath = DetermineExtractionFolder(isExtractAction, info);
            String extractionFileName = info.ProductName + " " + info.ProductVersion.ToString(CultureInfo.InvariantCulture) + PackageExtension;
            String fullPath = Path.Combine(extractionPath, extractionFileName);

            using (FileStream writer = File.OpenWrite(fullPath))
            {
                writer.Write(Resources.Package, 0, Resources.Package.Length);
            }

            if (isExtractAction)
            {
                return;
            }
            
            Boolean isUninstallAction = DetermineUninstallAction(PackageExtension, args);

            if (isUninstallAction)
            {
                String additionalArguments = BuildCommandLineArguments(args, true);
                
                // Invoke msiexec to uninstall the application
                ProcessStartInfo installProcess = new ProcessStartInfo("msiexec", "/x \"" + fullPath + "\" " + additionalArguments);

                Process.Start(installProcess);
            }
            else
            {
                String additionalArguments = BuildCommandLineArguments(args, false);

                // Simply execute this file path using the default actions defined by Windows
                ProcessStartInfo installProcess = new ProcessStartInfo(fullPath, additionalArguments);

                Process.Start(installProcess);
            }
        }

        /// <summary>
        /// Builds the command line arguments.
        /// </summary>
        /// <param name="arguments">
        /// The arguments.
        /// </param>
        /// <param name="skipFirst">
        /// If set to <c>true</c> skip the first argument.
        /// </param>
        /// <returns>
        /// A <see cref="String"/> instance.
        /// </returns>
        private static String BuildCommandLineArguments(String[] arguments, Boolean skipFirst)
        {
            String result = String.Empty;
            Int32 startIndex = 0;

            if (skipFirst)
            {
                startIndex = 1;
            }

            for (Int32 index = startIndex; index < arguments.Length; index++)
            {
                String argument = arguments[index];

                if (String.IsNullOrEmpty(argument))
                {
                    continue;
                }

                if (argument.Contains(" "))
                {
                    result = String.Concat(result, "\"", argument, "\" ");
                }
                else
                {
                    result = String.Concat(result, argument, " ");
                }
            }

            return result.Trim();
        }

        /// <summary>
        /// Determines the extract action.
        /// </summary>
        /// <param name="arguments">
        /// The arguments.
        /// </param>
        /// <returns>
        /// A <see cref="Boolean"/> instance.
        /// </returns>
        private static Boolean DetermineExtractAction(String[] arguments)
        {
            if (arguments == null)
            {
                return false;
            }

            if (arguments.Length == 0)
            {
                return false;
            }

            if (arguments[0].Equals("extract", StringComparison.OrdinalIgnoreCase))
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Determines the extraction folder.
        /// </summary>
        /// <param name="isExtractAction"><c>true</c> if the action is a simple extraction; otherwise, <c>false</c>.</param>
        /// <param name="info">The file version information.</param>
        /// <returns>The extraction path.</returns>
        private static String DetermineExtractionFolder(Boolean isExtractAction, FileVersionInfo info)
        {
            if (isExtractAction)
            {
                // Return the location of the current assembly
                String assemblyLocation = Assembly.GetExecutingAssembly().Location;

                return Path.GetDirectoryName(assemblyLocation);
            }

            String extractionPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles);

            extractionPath = Path.Combine(extractionPath, info.CompanyName);

            if (Directory.Exists(extractionPath) == false)
            {
                Directory.CreateDirectory(extractionPath);
            }

            return extractionPath;
        }

        /// <summary>
        /// Determines the uninstall action.
        /// </summary>
        /// <param name="packageExtension">
        /// The package extension.
        /// </param>
        /// <param name="arguments">
        /// The arguments.
        /// </param>
        /// <returns>
        /// A <see cref="Boolean"/> instance.
        /// </returns>
        private static Boolean DetermineUninstallAction(String packageExtension, String[] arguments)
        {
            if (arguments == null)
            {
                return false;
            }

            if (arguments.Length == 0)
            {
                return false;
            }

            if (packageExtension.Equals(".msi", StringComparison.OrdinalIgnoreCase) == false)
            {
                return false;
            }

            if (arguments[0].Equals("uninstall", StringComparison.OrdinalIgnoreCase))
            {
                return true;
            }

            return false;
        }
    }
}